using System;
using System.Collections.Generic;

namespace Hive.Core {

    public enum Direction
    {
        North,
        South,
        East,
        West
    }

    public static class DirectionExtensions
    {

        public static char ToChar(this Direction self)
        {
            switch (self)
            {
                case Direction.East:
                    return 'e';

                case Direction.North:
                    return 'n';

                case Direction.South:
                    return 's';

                case Direction.West:
                    return 'w';

                default:
                    throw new ArgumentException("Unknown direction", "self");
            }
        }
    }

	public class Location : IEquatable<Location> {

		/// <summary>
		/// Gets the row of this location.
		/// </summary>
		public int Row { get; private set; }

		/// <summary>
		/// Gets the column of this location.
		/// </summary>
		public int Col { get; private set; }

        public Location(Location other): this(other.Row, other.Col)
        {

        }
		public Location (int row, int col) {
			this.Row = row;
			this.Col = col;
		}

		public override bool Equals (object obj) {
			if (ReferenceEquals (null, obj))
				return false;
			if (ReferenceEquals (this, obj))
				return true;
			if (obj.GetType() != typeof (Location))
				return false;

			return Equals ((Location) obj);
		}

		public bool Equals (Location other) {
			if (ReferenceEquals (null, other))
				return false;
			if (ReferenceEquals (this, other))
				return true;

			return other.Row == this.Row && other.Col == this.Col;
		}

		public override int GetHashCode()
		{
			unchecked {
				return (this.Row * 397) ^ this.Col;
			}
		}

        public override string ToString()
        {
            return string.Format("({0}, {1})", Row, Col);
        }

        public static bool operator ==(Location a, Location b)
        {
            if (ReferenceEquals(null, a) && ReferenceEquals(null, b))
                return true;

            if (ReferenceEquals(a, null))
                return false;
            if (ReferenceEquals(b, null))
                return false;

            return a.Equals(b);
        }

        public static bool operator !=(Location a, Location b)
        {
            return !(a == b);
        }

        public static Location operator +(Location a, Location b)
        {
            return new Location(a.Row + b.Row, a.Col + b.Col);
        }
	}

	public class TeamLocation : Location, IEquatable<TeamLocation> {
		/// <summary>
		/// Gets the team of this ant.
		/// </summary>
		public int Team { get; private set; }

		public TeamLocation (int row, int col, int team) : base (row, col) {
			this.Team = team;
		}

		public bool Equals(TeamLocation other) {
			return base.Equals (other) && other.Team == Team;
		}

		public override int GetHashCode()
		{
			unchecked {
				int result = this.Col;
				result = (result * 397) ^ this.Row;
				result = (result * 397) ^ this.Team;
				return result;
			}
		}
	}
	
	public class AntLocation : TeamLocation, IEquatable<AntLocation> {
		public AntLocation (int row, int col, int team) : base (row, col, team) {
		}

		public bool Equals (AntLocation other) {
			return base.Equals (other);
		}
	}

	public class AntHillLocation : TeamLocation, IEquatable<AntHillLocation> {
		public AntHillLocation (int row, int col, int team) : base (row, col, team) {
		}

		public bool Equals (AntHillLocation other) {
			return base.Equals (other);
		}
	}
}

